package com.terrynoya.fight.char
{
	import com.terrynoya.coreLib.MHashMap;
	import com.terrynoya.fight.animations.AnimationId;
	import com.terrynoya.fight.animations.AnimationManager;
	import com.terrynoya.fight.animations.IAirInfo;
	import com.terrynoya.fight.combat.CharacterBind;
	import com.terrynoya.fight.combat.CharacterDimension;
	import com.terrynoya.fight.combat.CharacterVariables;
	import com.terrynoya.fight.combat.DefensiveInfo;
	import com.terrynoya.fight.combat.EntityCollection;
	import com.terrynoya.fight.combat.FightEngine;
	import com.terrynoya.fight.combat.Helper;
	import com.terrynoya.fight.combat.OffensiveInfo;
	import com.terrynoya.fight.combat.PlayerConstants;
	import com.terrynoya.fight.commands.CommandManager;
	import com.terrynoya.fight.emuns.Facing;
	import com.terrynoya.fight.emuns.MoveType;
	import com.terrynoya.fight.emuns.PhysicsEnum;
	import com.terrynoya.fight.emuns.PlayerControl;
	import com.terrynoya.fight.emuns.StateTypeEnum;
	import com.terrynoya.fight.stateMachine.StateMachine;
	import com.terrynoya.fight.stateMachine.StateNumber;
	import com.terrynoya.fight.stateMachine.triggers.StateNo;
	import com.terrynoya.fight.stateMachine.triggers.StateType;
	import com.terrynoya.fight.system.camera.MCamera;
	import com.terrynoya.fight.test.CollisionEntity;
	import com.terrynoya.fight.util.Misc;
	import com.terrynoya.geom.MVector2D;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.geom.Rectangle;

	public class Character extends Entity
	{
		private var _positionFreeze:Boolean;
		private var _pushFlag:Boolean;
		private var _id:String;
		private var _moveType:int;
		private var _inHitPause:Boolean;
		private var _offensiveInfo:OffensiveInfo;
		private var _defensiveInfo:DefensiveInfo;
		private var _playerControl:int;
		private var _life:int;
		private var _playerConst:PlayerConstants;
		private var _stateManager:StateMachine;
		private var _variables:CharacterVariables;
		private var _render:ICharaterRender;
		private var _view:Sprite;
		private var _commandManager:CommandManager;
		private var _currentInput:int;
		private var _dimension:CharacterDimension;
		private var _bind:CharacterBind;
		private var _updatedAnimation:Boolean;
		
		public static const SCALE_LEFT:MVector2D = new MVector2D(-1,1);
		public static const SCALE_RIGHT:MVector2D = new MVector2D(1,1);
		
		private var _helpers:MHashMap;
		
		public function Character(engine:FightEngine,render:ICharaterRender = null)
		{
			super(engine);
			this._helpers = new MHashMap();
			this._view = new Sprite(); 
			this._render = render;
			this._stateManager = new StateMachine(this);
			this._pushFlag = false;
			this._offensiveInfo = new OffensiveInfo(this);
			this._defensiveInfo = new DefensiveInfo(this);
			this._playerControl = PlayerControl.InControl;
			this._variables = new CharacterVariables();
			this._commandManager = new CommandManager();
			this._dimension = new CharacterDimension();
			this._bind = new CharacterBind(this);
		}
		
		public function get helpers():MHashMap
		{
			return _helpers;
		}
		
		public function addHelper(helper:Helper):void
		{
			var arr:Array = this.getHelperList(helper.data.helperId);
			arr.push(helper);
		}
		
		public function removeHelper(helper:Helper):void
		{
			var arr:Array = this.getHelperList(helper.data.helperId);
			var index:int = arr.indexOf(helper);
			arr.splice(index,1);
		}
		
		public function getHelperLength(id:int):int
		{
			var list:Array = null;
			if(id > 0)
			{
				list = this.getHelperList(id);
				return list.length;
			}
			else
			{
				var count:int = 0;
				for (var i:int = 0; i < this._helpers.length; i++) 
				{
					list = this.helpers.getItemAt(i);
					count += list.length;
				}
				return count;
			}
		}
		
		private function getHelperList(id:int):Array
		{
			if(!this._helpers.containsKey(id))
			{
				this._helpers.put(id,new Array());
			}
			var helperList:Array = this._helpers.getValue(id);
			return helperList;
		}

		public function get updatedAnimation():Boolean
		{
			return _updatedAnimation;
		}

		/**
		 * 将人物图片坐标转换到舞台坐标 
		 * @param item
		 * @param character
		 * @return 
		 * 
		 */		
		private function localToGlobal(axis:MVector2D,offset:MVector2D):MVector2D
		{
			var pos:MVector2D = this.position;
			var scale:MVector2D = this.getScaleByFacing(this.facing);
			var stageVec:MVector2D = new MVector2D(0,this.engine.stage.height);
			var rlt:MVector2D = pos.substract(axis.substract(offset).mutiply(scale)).add(stageVec);
			return rlt;
		}
		
		private function getScaleByFacing(facing:int):MVector2D
		{
			if(facing == Facing.LEFT)
			{
				return SCALE_LEFT;
			}
			else
			{
				return SCALE_RIGHT;
			}
		}
		
		public function get bind():CharacterBind
		{
			return _bind;
		}

		public function get dimension():CharacterDimension
		{
			return _dimension;
		}

		public function setCommands(commands:Array):void
		{
			this._commandManager.setCommands(commands);
		}
		
		public function recieveInput(button:int,pressed:Boolean):void
		{
			if(pressed)	
			{
				this._currentInput = this._currentInput | button;
			}
			else
			{
				this._currentInput = this._currentInput & (~button);	
			}
		}
		
		public function get commandManager():CommandManager
		{
			return _commandManager;
		}

		public function get render():ICharaterRender
		{
			return _render;
		}

		public function set render(value:ICharaterRender):void
		{
			_render = value;
		}
		
		public function get view():DisplayObject 
		{
//			return this._render.rendered;
			return this._view;
		}
		
		public function getTargets(targetId:int):Array
		{
			var offList:Array = this.offensiveInfo.targetList;
			if(targetId > 0)
			{
				var rlt:Array = new Array();
				for (var i:int = 0; i < offList.length; i++) 
				{
					var target:Character = offList[i];
					if(target.defensiveInfo.hitDef.targetId == targetId)
					{
						rlt.push(target);
					}
//					if(target.id == targetId.toString())
//					{
//						rlt.push(target);
//					}
				}
				return rlt;
			}
			else
			{
				return offList.concat();
			}
		}

		public function getOpponent():Character
		{
			var rlt:Character = null;
			for (var i:int = 0; i < this.engine.entities.length; i++) 
			{
				var entity:Entity = this.engine.entities.getChildAt(i);
				var chara:Character = entity as Character;
				if(this == chara)
				{
					continue;
				}
				if(chara != null)
				{
					rlt = chara;
					break;
				}
			}
			return rlt;
		}
		
		public function get variables():CharacterVariables
		{
			return _variables;
		}

		public function get stateManager():StateMachine
		{
			return _stateManager;
		}
		
		public function set stateManager(value:StateMachine):void
		{
			_stateManager = value;
		}
		
		public function get playerConst():PlayerConstants
		{
			return _playerConst;
		}

		public function set playerConst(value:PlayerConstants):void
		{
			_playerConst = value;
		}

		public function get life():int
		{
			return _life;
		}

		public function set life(value:int):void
		{
			_life = value;
		}

		public function get playerControl():int
		{
			return _playerControl;
		}

		public function set playerControl(value:int):void
		{
			_playerControl = value;
		}

		public function get defensiveInfo():DefensiveInfo
		{
			return _defensiveInfo;
		}

		public function get offensiveInfo():OffensiveInfo
		{
			return _offensiveInfo;
		}

		public function set offensiveInfo(value:OffensiveInfo):void
		{
			_offensiveInfo = value;
		}

		public function get inHitPause():Boolean
		{
			return _inHitPause;
		}

		public function get moveType():int
		{
			return _moveType;
		}

		public function set moveType(value:int):void
		{
			if(_moveType == MoveType.BeingHit && value != MoveType.BeingHit)
			{
				this.removeFromOthersTargetLists();
			}
			_moveType = value;
		}

		public function get id():String
		{
			return _id;
		}

		public function set id(value:String):void
		{
			_id = value;
		}

		public function get pushFlag():Boolean
		{
			return _pushFlag;
		}

		public function set pushFlag(value:Boolean):void
		{
			_pushFlag = value;
		}

		override public function cleanUp():void
		{
			if(this.offensiveInfo.hitPauseTime > 1)
			{
				trace("this.offensiveInfo.hitPauseTime",this.offensiveInfo.hitPauseTime);
				this._inHitPause = true;
				this.offensiveInfo.hitPauseTime --;
			}
			else 
			{
				this._inHitPause = false;
				this.offensiveInfo.hitPauseTime = 0;
			}
			if(this.inHitPause == false)
			{
				this.pushFlag = false;
				this.doFriction();
			}
		}
		
		private function doFriction():void
		{
			switch(this.physics)
			{
				case PhysicsEnum.Standing:
				{
					this.velocity = this.velocity.mutiply(new MVector2D(this._playerConst.standFriction,0));
					this.zeroCheckVelocity();
					break;
				}
				case PhysicsEnum.Crouching:
				{
					this.velocity = this.velocity.mutiply(new MVector2D(this._playerConst.crunchFriction,0));
					this.zeroCheckVelocity();
					break;
				}
				case PhysicsEnum.Airborne:
				{
//					this.velocity = this.velocity.add(new MVector2D(0,GRAVITY_ACC));
					this.velocity = this.velocity.add(new MVector2D(0,this.playerConst.vertAcceleration));
					break;
				}
			}
		}
		
		override protected function bounding():void
		{
			var camera:MCamera = this.engine.camera;
			var camLeft:Number = camera.left;
			var camRight:Number = camera.right;
			var newLeft:Number = camLeft - this.getLeftEdgePosition(true);
			var newRight:Number = camRight - this.getRightEdgePosition(true);
			
			if(this.getLeftEdgePosition(true) < camLeft)
			{
				this.position.x += newLeft; 
			}
			if(this.getRightEdgePosition(true) > camRight)
			{
				this.position.x += newRight;
			}
		}
		
		public function getLeftEdgePosition(body:Boolean):Number
		{
			var pos:Number;
			if(this.facing == Facing.LEFT)
			{
				pos = this.position.x - this.engine.stage.leftEdgeDistance;
				if(body == true)
				{
					pos -= this._dimension.frontEdgeWidth;	
				}
				return pos;
			}
			if(this.facing == Facing.RIGHT)
			{
				pos = this.position.x - this.engine.stage.leftEdgeDistance;
				if(body == true)
				{
					pos -= this._dimension.backEdgeWidth;
				}
				return pos;
			}
			return 0;
		}
		
		public function getRightEdgePosition(body:Boolean):Number
		{
			var pos:Number;
			if(this.facing == Facing.LEFT)
			{
				pos = this.position.x + this.engine.stage.rightEdgeDistance;
				if(body == true)
				{
					pos += this._dimension.backEdgeWidth;	
				}
				return pos;
			}
			if(this.facing == Facing.RIGHT)
			{
				pos = this.position.x + this.engine.stage.rightEdgeDistance;
				if(body == true)
				{
					pos += this._dimension.frontEdgeWidth;
				}
				return pos;
			}
			return 0;
		}
		
		private function zeroCheckVelocity():void
		{
			var vx:Number = this.velocity.x;
			var fit:Boolean = vx < 0.1 && vx > -0.1;
			this.velocity.x = fit ? 0 : vx;
		}
		
		override public function updateInput():void
		{
			this._commandManager.update(this._currentInput,this.facing,this.inHitPause);
		}
		
		public function setForeignAnimation(manager:AnimationManager,aniId:int,elemId:int):void
		{
			this.animationManager.setForeignAnimation(manager,aniId,elemId);
		}
		
		override public function updateState():void
		{
			this.bind.update();
			this.stateManager.run(this._inHitPause);
			if(!this._inHitPause)
			{
				this.offensiveInfo.update();
				this.defensiveInfo.update();
			}
			this.collision = this.makeCollision();
		}
		
		override public function updateAnimations():void
		{
			if(!this.inHitPause)
			{
				super.updateAnimations();
				this._updatedAnimation = true;
			}
			else
			{
				this._updatedAnimation = false;
			}
		}
		
		override public function updatePhysics():void
		{
			if(this.inHitPause == true || this.defensiveInfo.hitShakeTime > 0)
			{
				return;
			}
			if(this._positionFreeze == false)
			{
				this.move(this.velocity);
			}
			
			switch(this.physics)
			{
				case PhysicsEnum.Standing:
				{
					break;
				}
			}
			this.handleTurning();
			this.handlePushing();
		}
		
		/**
		 * 在对手背后的时候转向 
		 * 
		 */		
		private function handleTurning():void
		{
			if(this.pushFlag == false)
			{
				return;
			}
			var opponent:Character = this.getOpponent();
			if(opponent == null)
			{
				return;
			}
			if(this.facing == Facing.RIGHT && this.position.x <= opponent.position.x)
			{
				return;
			}
			else if(this.facing == Facing.LEFT && this.position.x >= opponent.position.x)
			{
				return;
			}
			
			//在站立状态&&动画不是转身	播放站立转身动画
			if(this.stateManager.currentState.id == StateNumber.Standing && this.animationManager.currentAni.id != AnimationId.Turning)
			{
				this.facing = Misc.flipFacing(this.facing);
				this.setLocalAnimation(AnimationId.Turning,0);
			}
			//在行走状态&&动画不是转身	播放站立转身动画
			if(this.stateManager.currentState.type == StateNumber.Walking && this.animationManager.currentAni.id != AnimationId.Turning)
			{
				this.facing = Misc.flipFacing(this.facing);
				this.setLocalAnimation(AnimationId.Turning,0);
			}
			//在下蹲状态&&动画不是转身	播放下蹲转身动画
			if(this.stateManager.currentState.type == StateTypeEnum.Crouching && this.animationManager.currentAni.id != AnimationId.CrounchTurning)
			{
				this.facing = Misc.flipFacing(this.facing);
				this.setLocalAnimation(AnimationId.CrounchTurning,0);
			}
		}
		
		/**
		 * 如果和对方接触并向前走，推对方 
		 * 
		 */		
		private function handlePushing():void
		{
			if(this._pushFlag == false)
			{
				return;
			}
			var len:int = this.engine.entities.length;
//			this.collision = this.makeCollision();
			
			for (var i:int = 0; i < len; i++) 
			{
				var entity:Entity = this.engine.entities.getChildAt(i);
				var target:Character = this.filterEntityAsCharacter(entity);
				if(target == null || target.pushFlag == false)
				{
					continue;
				}
//				var targetColns:CollisionEntity = target.makeCollision();
				var targetColns:CollisionEntity = target.collision;
				if(targetColns == null)
				{
					break;
				}
				if(collision == null)
				{
					continue;
				}
				var hitted:Boolean = collision.hitTestNormal(targetColns);
				if(!hitted)
				{
					continue;
				}	
				var lpos:Number = 0;
				var rpos:Number = 0;
				var overlap:Number = 0;
				var actualpush:MVector2D;
				var reversePush:Number = 0;
				if(this.position.x >= target.position.x)
				{
					lpos = this.getLeftLocation();
					rpos = target.getRightLocation();
					overlap = rpos - lpos;
					if(overlap > 0)
					{
						actualpush = target.moveLeft(new MVector2D(overlap,0));
						if(actualpush.x != -overlap)
						{
							reversePush = overlap - actualpush.x;
							entity.moveRight(new MVector2D(reversePush,0));
						}
					}
				}
				else
				{
					lpos = this.getRightLocation();
					rpos = target.getLeftLocation(); 
					overlap = lpos - rpos;
					if(overlap > 0)
					{
						actualpush = target.moveRight(new MVector2D(overlap,0));
						if(actualpush.x != overlap)
						{
							reversePush = overlap - actualpush.x;
							entity.moveLeft(new MVector2D(reversePush,0));
						}
					}
				}
			}
		}
		
		public function filterEntityAsCharacter(entity:Entity):Character
		{
			var isChara:Boolean = entity is Character;
			if(!isChara)	
			{
				return null;
			}
			if(Character(entity).team == this.team) 
			{
				return null;
			}
			return Character(entity);
		}
		
		override public function draw():void
		{
			this._render.draw(this,this._view);
		}
		
		private function getRightLocation():Number
		{
			if(this.facing == Facing.RIGHT)
			{
				return this.getFrontLocation();
			}
			else
			{
				return this.getBackLocation();
			}
		}
		
		private function getLeftLocation():Number
		{
			if(this.facing == Facing.RIGHT)
			{
				return this.getBackLocation();
			}
			else
			{
				return this.getFrontLocation();
			}
		}
		
		public function getFrontLocation():Number
		{
			if(this.facing == Facing.RIGHT)
			{
				return this.position.x + this._dimension.getFrontWidth(this.state);
			}
			else
			{
				return this.position.x - this._dimension.getFrontWidth(this.state);
			}
		}
		
		public function getBackLocation():Number
		{
			if(this.facing == Facing.RIGHT)
			{
				return this.position.x + this._dimension.getBackWidth(this.state);
			}
			else
			{
				return this.position.x - this._dimension.getBackWidth(this.state);
			}
		}
		
		private function removeFromOthersTargetLists():void
		{
			var entities:EntityCollection = this.engine.entities;
			for (var i:int = 0; i < entities.length; i++) 
			{
				var entity:Entity = entities.getChildAt(i);
				var chara:Character = entity as Character;
				if(chara == null)
				{
					continue;
				}
				chara.offensiveInfo.removeFromTargetList(this);
			}
		}
		
		private function updateView(name:String):void
		{
		}
	}
}